package org.hrqing.chess.frame.listener;

import lombok.extern.slf4j.Slf4j;
import org.hrqing.chess.config.props.SystemConfigProps;
import org.hrqing.chess.entity.LogPiece;
import org.hrqing.chess.frame.CenterBackgroundPanel;
import org.hrqing.chess.frame.ChessLabel;
import org.hrqing.chess.frame.MainFrame;
import org.hrqing.chess.service.GameService;
import org.hrqing.chess.service.LogService;
import org.hrqing.chess.service.PikaFishService;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Map;
import java.util.concurrent.atomic.AtomicReference;

/**
 * @author Hrqing
 */
@Slf4j
public class CenterMouseListener extends MouseAdapter {

    private final CenterBackgroundPanel panel;
    private final GameService gameService;
    private final LogService logService;
    private final PikaFishService pikaFishService;
    private final SystemConfigProps systemConfigProps;
    private final JLabel statusLabel;
    private JLabel imageLabel;
    private BufferedImage originalImage;
    private Timer scaleTimer;
    private Timer moveTimer;

    public CenterMouseListener(CenterBackgroundPanel panel, JLabel statusLabel, SystemConfigProps systemConfigProps, GameService gameService, LogService logService, PikaFishService pikaFishService) {
        this.panel = panel;
        this.systemConfigProps = systemConfigProps;
        this.gameService = gameService;
        this.logService = logService;
        this.pikaFishService = pikaFishService;
        this.statusLabel = statusLabel;
    }

    @Override
    public void mouseClicked(MouseEvent e) {
        Point clickPoint = e.getPoint();
        int x = CenterBackgroundPanel.getColumnIndex(clickPoint.x);
        int y = CenterBackgroundPanel.getRowIndex(clickPoint.y);

        int columnSum = CenterBackgroundPanel.getColumnSum(x);
        int rowSum = CenterBackgroundPanel.getRowSum(y);

        ChessLabel component = (ChessLabel) findDeepestComponentAt(panel, clickPoint);
        ChessLabel selected = MainFrame.selected();
        // 没有选择棋子 并且点击处为空  不做操作
        if (component == null && selected == null) {
            return;
        }
        // 已经选择棋子 点击的位置为空    进行移动
        if (component == null) {
            // 将军检查
            if (gameService.killCheck(panel, selected.getColor(), selected, x, y)) {
                Map<ChessLabel.Color, String> simple = selected.getPurpose().getCname();
                statusLabel.setText(selected.getColor().getSimple() + simple.get(selected.getColor()) + ":不能移动");
                return;
            }
            if (gameService.rule(panel, selected, null, x, y)) {
                // 移动停止动画
                if (scaleTimer != null) {
                    scaleTimer.stop();
                    imageLabel.setIcon(new ImageIcon(originalImage));
                }
                String[] split = selected.getId().split("-");
                int selectX = Integer.parseInt(split[0]);
                int selectY = Integer.parseInt(split[1]);
                int selectColumnSum = CenterBackgroundPanel.getColumnSum(selectX);
                int selectRowSum = CenterBackgroundPanel.getRowSum(selectY);

                log.info("start:{},{} {},{}", selectX, selectY, selectColumnSum, selectRowSum);

                selected.setVisible(false);
                panel.repaint();

                if (systemConfigProps.getAnimation().isEnable()) {
                    ChessLabel clone = selected.clone();
                    clone.setVisible(true);
                    String[] cloneSplit = clone.getId().split("-");
                    int cloneX = Integer.parseInt(cloneSplit[0]);
                    int cloneY = Integer.parseInt(cloneSplit[1]);
                    ChessLabel.insert(panel, clone, cloneX, cloneY);
                    panel.repaint();

                    animateMove(clone, x, y, selectColumnSum, selectRowSum, columnSum, rowSum);
                }else {
                    animateMoveCallback(x, y);
                }

            }
        }
        // 已经选择棋子  点击位置为棋子  棋子颜色一样  切换棋子
        if (component != null && selected != null && component.getColor().equals(selected.getColor())) {
            MainFrame.select(null);
            if (scaleTimer != null) {
                scaleTimer.stop();
                imageLabel.setIcon(new ImageIcon(originalImage));
            }
            animateSelection(component);
        }
        // 已经选择棋子  点击位置为棋子  棋子颜色不一样
        if (component != null && selected != null && !component.getColor().equals(selected.getColor())) {
            // 将军检查
            if (gameService.killCheck(panel, selected.getColor(), selected, x, y)) {
                Map<ChessLabel.Color, String> simple = selected.getPurpose().getCname();
                statusLabel.setText(selected.getColor().getSimple() + simple.get(selected.getColor()) + ":不能移动");
                return;
            }
            if (gameService.rule(panel, selected, component, x, y)) {
                // 移动停止动画
                if (scaleTimer != null) {
                    scaleTimer.stop();
                    imageLabel.setIcon(new ImageIcon(originalImage));
                }
                selected.setVisible(false);
                panel.repaint();

                String[] split = selected.getId().split("-");
                int selectX = Integer.parseInt(split[0]);
                int selectY = Integer.parseInt(split[1]);
                int selectColumnSum = CenterBackgroundPanel.getColumnSum(selectX);
                int selectRowSum = CenterBackgroundPanel.getRowSum(selectY);

                log.info("start:{},{} {},{}", selectX, selectY, selectColumnSum, selectRowSum);

                if (systemConfigProps.getAnimation().isEnable()) {
                    ChessLabel clone = selected.clone();
                    clone.setVisible(true);
                    String[] cloneSplit = clone.getId().split("-");
                    int cloneX = Integer.parseInt(cloneSplit[0]);
                    int cloneY = Integer.parseInt(cloneSplit[1]);
                    ChessLabel.insert(panel, clone, cloneX, cloneY);
                    panel.repaint();
                    animateMove(clone, x, y, selectColumnSum, selectRowSum, columnSum, rowSum);
                }else {
                    animateMoveCallback(x, y);
                }

            }
        }
        // 没有选择棋子  点击位置为棋子   选中棋子
        if (component != null && component.isSelected() && selected == null){
            if (scaleTimer != null) {
                scaleTimer.stop();
                imageLabel.setIcon(new ImageIcon(originalImage));
            }
            animateSelection(component);
        }
    }

    private void move(ChessLabel selected, int x, int y, int columnSum, int rowSum) {
        selected.setVisible(false);
        panel.repaint();

        String[] split = selected.getId().split("-");
        int selectX = Integer.parseInt(split[0]);
        int selectY = Integer.parseInt(split[1]);
        int selectColumnSum = CenterBackgroundPanel.getColumnSum(selectX);
        int selectRowSum = CenterBackgroundPanel.getRowSum(selectY);

        ChessLabel selectClone = selected.clone();

        log.info("start:{},{} {},{}", selectX, selectY, selectColumnSum, selectRowSum);

        if (systemConfigProps.getAnimation().isEnable()) {
            ChessLabel clone = selected.clone();
            clone.setVisible(true);
            String[] cloneSplit = clone.getId().split("-");
            int cloneX = Integer.parseInt(cloneSplit[0]);
            int cloneY = Integer.parseInt(cloneSplit[1]);
            ChessLabel.insert(panel, clone, cloneX, cloneY);
            panel.repaint();
            animateMove(clone, x, y, selectColumnSum, selectRowSum, columnSum, rowSum);
        }else {
            animateMoveCallback(x, y);
        }
//        ChessLabel selectClone = selected.clone();
        logService.log(panel, selectClone, x, y);

        log.info("end:{},{} {},{}", x, y, columnSum, rowSum);
    }

    private void bot() {
        ChessLabel.Color color = panel.getColor();
        ChessLabel.Color executing = panel.getExecuting();
        if ((color.equals(ChessLabel.Color.RED) && executing.equals(ChessLabel.Color.BLACK))
            || (color.equals(ChessLabel.Color.BLACK) && executing.equals(ChessLabel.Color.RED))) {
            java.util.List<LogPiece> logPieces = logService.findLogPieceByLogId(panel.getGameId());
            try {
                PikaFishService.AnalysisResult result = pikaFishService.logAnalyze(panel.getDepth(), logPieces);
                PikaFishService.MoveResult move = result.getMove();
                int columnSum = CenterBackgroundPanel.getColumnSum(move.getMex());
                int rowSum = CenterBackgroundPanel.getRowSum(move.getMey());

                ChessLabel selected = null;
                for (Component component : panel.getComponents()) {
                    if (component instanceof ChessLabel chess) {
                        if (chess.getId().equals(move.getMsx() + "-" + move.getMsy())) {
                            selected = chess;
                            break;
                        }
                    }
                }
                MainFrame.select(selected);

                selected.setVisible(false);
                panel.repaint();

                String[] split = selected.getId().split("-");
                int selectX = Integer.parseInt(split[0]);
                int selectY = Integer.parseInt(split[1]);
                int selectColumnSum = CenterBackgroundPanel.getColumnSum(selectX);
                int selectRowSum = CenterBackgroundPanel.getRowSum(selectY);

                log.info("start:{},{} {},{}", selectX, selectY, selectColumnSum, selectRowSum);

                if (systemConfigProps.getAnimation().isEnable()) {
                    ChessLabel clone = selected.clone();
                    clone.setVisible(true);
                    String[] cloneSplit = clone.getId().split("-");
                    int cloneX = Integer.parseInt(cloneSplit[0]);
                    int cloneY = Integer.parseInt(cloneSplit[1]);
                    ChessLabel.insert(panel, clone, cloneX, cloneY);
                    panel.repaint();
                    animateMove(clone, move.getMex(), move.getMey(), selectColumnSum, selectRowSum, columnSum, rowSum);
                }else {
                    animateMoveCallback(move.getMex(), move.getMey());
                }

                ChessLabel selectClone = selected.clone();
                logService.log(panel, selectClone, move.getMex(), move.getMey());

            }catch (Exception e) {
                JOptionPane.showMessageDialog(panel, "人机调用异常", "错误", JOptionPane.ERROR_MESSAGE);
            }
        }
    }

    private java.awt.Component findDeepestComponentAt(Container parent, Point p) {
        for (java.awt.Component comp : parent.getComponents()) {
            Rectangle bounds = comp.getBounds();
            if (bounds.contains(p)) {
                Point relativePoint = new Point(p.x - bounds.x, p.y - bounds.y);
                if (comp instanceof Container) {
                    java.awt.Component child = findDeepestComponentAt((Container) comp, relativePoint);
                    return child != null ? child : comp;
                }
                return comp;
            }
        }
        return null;
    }

    private void animateMoveCallback(int x, int y) {
        Component will = null;
        for (Component component : panel.getComponents()) {
            if (component instanceof ChessLabel chess) {
                if (chess.getId().equals(x + "-" + y)) {
                    will = component;
                    break;
                }
            }
        }
        if (will != null) {
            panel.remove(will);
        }

        panel.remove(MainFrame.selected());

        MainFrame.selected().setVisible(true);
        MainFrame.selected().setId(Integer.toString(x)  + "-" + Integer.toString(y));
        ChessLabel.insert(panel, MainFrame.selected(), x, y);
        panel.revalidate();

        ChessLabel selected = MainFrame.selected().clone();
        logService.log(panel, selected, x, y);

        // 将军检查
        if (gameService.killCheck(panel, selected.enemyColor(), selected, x, y)) {
            Map<ChessLabel.Color, String> simple = selected.getPurpose().getCname();
            statusLabel.setText(selected.getColor().getSimple() + simple.get(selected.getColor()) + ":将军");
        }

        switch (selected.getColor()) {
            case RED -> {
                ChessLabel.selected(panel, ChessLabel.Color.BLACK);
                panel.setExecuting(ChessLabel.Color.BLACK);
                panel.getExecuteTime().setBlack(System.currentTimeMillis());
            }
            case BLACK -> {
                ChessLabel.selected(panel, ChessLabel.Color.RED);
                panel.setExecuting(ChessLabel.Color.RED);
                panel.getExecuteTime().setRed(System.currentTimeMillis());
            }
        }

        MainFrame.select(null);

        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                bot();
            }
        });
    }

    private void animateMove(ChessLabel imageLabel, int mx, int my, int startX, int startY, int endX, int endY) {
        final AtomicReference<Double> progress = new AtomicReference<>(0.0);
        Timer timer = new Timer(45, new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                progress.set(BigDecimal.valueOf(progress.get()).add(new BigDecimal("0.2")).setScale(2, RoundingMode.DOWN).doubleValue());

                // 坐标插值计算
                int x = startX + (int)((endX - startX) * progress.get());
                int y = startY + (int)((endY - startY) * progress.get());
                log.info("progress:{} {},{}", progress.get(), x, y);
                // 更新组件位置
                imageLabel.setLocation(x,  y);
                // 终止条件
                if (progress.get() >= 1.0) {
                    moveTimer.stop();
                    panel.remove(imageLabel);
                    animateMoveCallback(mx, my);
                }

            }
        });
        timer.start();
        this.moveTimer = timer;
    }

    private void animateSelection(ChessLabel imageLabel) {
        this.imageLabel = imageLabel;
        MainFrame.select(imageLabel);
        // 预加载图像资源
        ImageIcon icon = (ImageIcon) imageLabel.getIcon();
        originalImage = new BufferedImage(
                icon.getIconWidth(),
                icon.getIconHeight(),
                BufferedImage.TYPE_INT_ARGB
        );
        originalImage.getGraphics().drawImage(icon.getImage(), 0, 0, null);

        // 量子化动画引擎（支持120FPS渲染）
        Timer timer = new Timer(80, new ActionListener() {
            float scale = 1.0f;
            final float MAX_SCALE = 0.9f; // 支持动态配置

            @Override
            public void actionPerformed(ActionEvent e) {
                // 应用缓动函数实现自然过渡
                scale = (scale <= MAX_SCALE) ? 1.0f : scale - 0.01f;

                // GPU加速的图像变换
                AffineTransform transform = new AffineTransform();
                transform.scale(scale, scale);

                // 实时生成缩放后图像
                BufferedImage scaledImage = new BufferedImage(
                        (int) (originalImage.getWidth() * scale),
                        (int) (originalImage.getHeight() * scale),
                        BufferedImage.TYPE_INT_ARGB
                );

                Graphics2D g2d = scaledImage.createGraphics();
                g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
                        RenderingHints.VALUE_INTERPOLATION_BILINEAR);
                g2d.drawImage(originalImage, transform, null);
                g2d.dispose();

                // 动态更新组件
                imageLabel.setIcon(new ImageIcon(scaledImage));
                imageLabel.repaint();

            }
        });
        timer.setCoalesce(true);  // 合并绘制事件
        timer.start();

        this.scaleTimer = timer;
    }
}
